// TSTreeView.cpp : implementation file
//

#include "stdafx.h"
#include "TSG.h"

#include "TSGDoc.h"
#include "TSTreeView.h"
#include "TreeNode.h"


// CTSTreeView

IMPLEMENT_DYNCREATE(CTSTreeView, CTreeView)

BEGIN_MESSAGE_MAP(CTSTreeView, CTreeView)
	ON_NOTIFY_REFLECT(TVN_SELCHANGED, &CTSTreeView::OnTvnSelchanged)
END_MESSAGE_MAP()

// CTreeAView construction/destruction

CTSTreeView::CTSTreeView()
{
	// TODO: add construction code here	
}

CTSTreeView::~CTSTreeView()
{
	TreeTerm();
}

BOOL CTSTreeView::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: Modify the Window class or styles here by modifying
	//  the CREATESTRUCT cs
	cs.style |= TVS_HASLINES|TVS_LINESATROOT|TVS_HASBUTTONS;

	return CTreeView::PreCreateWindow(cs);
}

void CTSTreeView::OnInitialUpdate()
{
	CTreeView::OnInitialUpdate();

	// TODO: Add your specialized code here and/or call the base class
	CTreeCtrl &tree = GetTreeCtrl();
	TreeInitial(&tree);
}




// CTSTreeView diagnostics

#ifdef _DEBUG
void CTSTreeView::AssertValid() const
{
	CTreeView::AssertValid();
}

void CTSTreeView::Dump(CDumpContext& dc) const
{
	CTreeView::Dump(dc);
}

CTSGDoc* CTSTreeView::GetDocument() const // non-debug version is inline
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CTSGDoc)));
	return (CTSGDoc*)m_pDocument;
}
#endif //_DEBUG


// CTSTreeView message handlers
void CTSTreeView::UpdateTree(CTreeNode* pNode)
{
	if(pNode)
	{
		CTreeNode *pParent, *pInsertAfter;
		DWORD parameter = pNode->GetItemData();
		if(parameter != 0)
		{
			BYTE table_id = parameter&0xFF;
			if(table_id == TABLE_PAT || table_id == TABLE_CAT || table_id == TABLE_PMT)
			{
				pNode->SetItemType(PSI);
			}
			else
			{
				pNode->SetItemType(SI);
			}
		}

		pParent = GetParentNode(pNode);
		pInsertAfter = GetInsertAfter(pNode);

		AddTreeNode(pNode, pParent, pInsertAfter);		
	}
}

static HTREEITEM g_TreeNodeStack[8] = {0};
static HTREEITEM* g_TreeStackTop = g_TreeNodeStack;
static HTREEITEM* g_TreeStackButtom = g_TreeNodeStack;
static void pushTreeNode(HTREEITEM hItem)
{
	if(g_TreeStackTop < g_TreeNodeStack + 8)
	{
		*g_TreeStackTop = hItem;
		g_TreeStackTop++;
	}
}
static HTREEITEM popTreeNode(void)
{
	HTREEITEM hItem = NULL;
	if(g_TreeStackTop > g_TreeNodeStack)
	{
		g_TreeStackTop--;
		hItem = *g_TreeStackTop;
		*g_TreeStackTop = NULL;
	}

	return hItem;
}


void CTSTreeView::OnTvnSelchanged(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
	CTSGDoc* pDoc = GetDocument();
	// TODO: Add your control notification handler code here
	if(pNMTreeView)
	{
		CTreeCtrl& tree = GetTreeCtrl();
		CTreeNode *pNode = (CTreeNode*)(pNMTreeView->itemNew.lParam);
		if(pNode && tree)
		{
			if(pNode->GetItemDataEx() != 0 && tree.GetChildItem(pNMTreeView->itemNew.hItem)==NULL)
			{
				CString text;
				DWORD parameter = pNode->GetItemData();
				USHORT pid = (parameter&0xFFFF0000)>>16;
				BYTE table_id = BYTE(parameter&0xFF);
				DWORD parameterEx = pNode->GetItemDataEx();
				USHORT value = (parameterEx&0xFFFF0000)>>16;
				BYTE version = (parameterEx&0xFF00)>>8;
				BYTE section_number = parameterEx&0xFF;

				int nIndex = pDoc->GetTableIndex(table_id);

				if(nIndex < (int)pDoc->GetDVBTableCount())
				{
					BYTE *pData = pDoc->GetSectionBuffer(pid, table_id, value, version, section_number);
					if(pData)
					{
						BOOL bNext = FALSE;
						char pLine[128] = {0};
						BYTE bPosition = 2;
						HTREEITEM hParent = (HTREEITEM)pNode->GetItemHandle();
						HTREEITEM hItem = NULL;

						bNext = pDoc->ParseDVBTable(nIndex, pData, pLine, bPosition);
						while(bNext)
						{
							//bPosition: 1-Upper, 2-current, 3-Lower
							CString str;
							str = pLine;
							if(str.GetLength() >0)
							{
								TVINSERTSTRUCT tvInsert;
								tvInsert.hParent = hParent;
								tvInsert.hInsertAfter = NULL;
								tvInsert.item.mask = TVIF_TEXT;
								tvInsert.item.pszText = str.AllocSysString();
								hItem = tree.InsertItem(&tvInsert);
								::SysFreeString(tvInsert.item.pszText);
								//tree.EnsureVisible(hItem);
							}

							if(bPosition == 1)
							{
								hParent = popTreeNode();
							}
							if(bPosition == 3)
							{
								pushTreeNode(hParent);
								hParent = hItem;
							}		

							bPosition = 2;
							bNext = pDoc->ParseDVBTable(nIndex, pData, pLine, bPosition);
						}
					}
				}
				else
				{
					text.Format(_T("{!!!Unknown Table}:[Section]PID:0x%04X, table id:0x%02X, parameter:0x%04X, version:0x%02X, sec_num:0x%02X"),\
						pid, table_id, value, version, section_number);

					TVINSERTSTRUCT tvInsert;
					tvInsert.hParent = (HTREEITEM)pNode->GetItemHandle();
					tvInsert.hInsertAfter = TVI_FIRST;
					tvInsert.item.mask = TVIF_TEXT;
					tvInsert.item.pszText = text.AllocSysString();
					HTREEITEM hParent = tree.InsertItem(&tvInsert);
					::SysFreeString(tvInsert.item.pszText);
				}
			}
		}
	}

	*pResult = 0;
}
